#include <algorithm/analytical_model/algorithm/cpu/VectorConvert.h>
#include <algorithm/analytical_model/algorithm/cuda/inter_op/Data.h>
#include <algorithm/analytical_model/algorithm/cuda/inter_op/receiver/ImagePlane.h>
#include <algorithm/analytical_model/algorithm/cuda/inter_op/utils/convert/receiver/ConvertReceiver.h>
#include <algorithm/analytical_model/algorithm/geometry/Rectangle3D.h>
#include <algorithm/shared/data/scene/Receiver.h>
#include <algorithm/shared/data/topology/geometry/Rectangle3D.h>
#include <utils/ParaUtils.h>

#include <array>

// #include <iostream>
// #include <utils/Format.h>

template <>
void solar::cuda::inter_op::convertReceiver(ImagePlane* input_ptr, solar::Receiver* output_ptr)
{
    auto input = *input_ptr;
    auto output = *output_ptr;
    const auto input_size = input.getSize();
    const auto input_normal = input.getNormal();
    const auto input_center = input.getPosition();
    const auto input_vertices = input.getVertices();
    const auto geometry_receiver = SOLAR_GET_VALUE2(solar, Receiver, geometry_, output);
    auto* rectangle3d_geometry = dynamic_cast<Rectangle3D*>(geometry_receiver.get());
    SOLAR_SET_VALUE2(solar, Rectangle3D, size_, cpu::toVec3(input_size), *rectangle3d_geometry)
    SOLAR_SET_VALUE2(solar, Rectangle3D, normal_, cpu::toVec3(input_normal), *rectangle3d_geometry)
    SOLAR_SET_VALUE2(solar, Rectangle3D, normal_, cpu::toVec3(input_center), *rectangle3d_geometry)
    const std::array output_vertices = {
        cpu::toVec3(input_vertices[0]), cpu::toVec3(input_vertices[1]),
        cpu::toVec3(input_vertices[2]), cpu::toVec3(input_vertices[3])};
    SOLAR_SET_VALUE2(solar, Rectangle3D, vertices_, output_vertices, *rectangle3d_geometry)
}

template <>
void solar::cuda::inter_op::convertReceiver(solar::Receiver* input_ptr, ImagePlane* output_ptr)
{
    const auto geometry_receiver = SOLAR_GET_VALUE2(solar, Receiver, geometry_, *input_ptr);
    auto* rectangle3d_geometry = dynamic_cast<Rectangle3D*>(geometry_receiver.get());
    const auto input_size = SOLAR_GET_VALUE2(solar, Rectangle3D, size_, *rectangle3d_geometry);
    const auto input_normal = SOLAR_GET_VALUE2(solar, Rectangle3D, normal_, *rectangle3d_geometry);
    const auto input_center = SOLAR_GET_VALUE2(solar, Rectangle3D, center_, *rectangle3d_geometry);
    const auto input_vertices =
        SOLAR_GET_VALUE2(solar, Rectangle3D, vertices_, *rectangle3d_geometry);
    output_ptr->setSize(cpu::toFloat3(input_size));
    output_ptr->setNormal(cpu::toFloat3(input_normal));
    output_ptr->setPosition(cpu::toFloat3(input_center));
    std::array<Float3, 4> vertices;
    std::transform(input_vertices.begin(), input_vertices.end(), vertices.begin(),
                   [](const Vec3& vec) { return cpu::toFloat3(vec); });
    output_ptr->setVertices(vertices);
}
